/*
 * SecureContainer.cpp
 *
 *  Created on: Aug 26, 2011
 *      Author: Gherman Alin
 */

#include "serialization.h"
#include "SecureContainer.h"
#include "../Crypto/all.h"
#include <sstream>

using namespace std;

namespace DataAccess {

const char * DEFAULT_PASSWORD = "jus4funUseDefaultPassword9372012";

const long NOT_ENCRYPTED = 0;
const long ENCRYPTED = 1;

SecureContainer::SecureContainer() :
		password(""), decrypted(false), loaded(false),
				_crypted(""), _encryptionType(NOT_ENCRYPTED) {
}

SecureContainer::SecureContainer(const string& _password) :
		password(_password), decrypted(false), loaded(false),
				_crypted(""), _encryptionType(NOT_ENCRYPTED) {
}

SecureContainer::~SecureContainer() {
}

void SecureContainer::setPassword(const std::string& _password) {
	password = _password;
}

bool SecureContainer::setPasswordAndDecrypt(const std::string& _password) {
	setPassword(_password);
	if (loaded && !decrypted) {
		return decrypt();
	}
	return true;
}

bool SecureContainer::hasPassword() {
	return password.length() > 0;
}

vector<string> SecureContainer::getKeys() {
	vector<string> keys(strData.getKeys());
	vector<string> rawKeys = rawData.getKeys();
	keys.insert(keys.end(), rawKeys.begin(), rawKeys.end());
	return keys;
}

bool SecureContainer::set(const string& key, const string& value) {
	if (rawData.contains(key)) {
		return false;
	}
	return strData.set(key, value);
}

bool SecureContainer::set(const string& key, const vector<char>& data) {
	if (strData.contains(key)) {
		return false;
	}
	return rawData.set(key, data);
}

bool SecureContainer::set(const std::string& key, std::istream& in) {
	if (strData.contains(key)) {
		return false;
	}
	std::vector<char> data;
	std::vector<char> buffer(BLOCK_SIZE);
	throw "NOT IMPLEMENTED";
	return rawData.set(key, data);
}

bool SecureContainer::remove(const string& key) {
	return rawData.remove(key) || strData.remove(key);
}

bool SecureContainer::getStr(const string& key, string& out) {
	return strData.get(key, out);
}

bool SecureContainer::getData(const string& key, vector<char>& out) {
	return rawData.get(key, out);
}

bool SecureContainer::getInOutstream(const std::string& key, std::ostream& out) {
	std::vector<char> data;
	bool ok = rawData.get(key, data);
	throw "NOT IMPLEMENTED";
	return ok;
}

void SecureContainer::encrypt() const {
	Crypto::SymetricCrypto cr;
	if (password.length() == 0) {
		cr.setPassword(DEFAULT_PASSWORD);
		_encryptionType = NOT_ENCRYPTED;
	} else {
		cr.setPassword(password);
		_encryptionType = ENCRYPTED;
	}
	std::ostringstream oss;
	OutArchive oarch(oss);
	oarch & strData;
	oarch & rawData;

	std::string uncrypted = oss.str();
	cr.encrypt(uncrypted, _crypted);
}

bool SecureContainer::decrypt() {
	if (_encryptionType == ENCRYPTED && !hasPassword()) {
		return false;
	}
	bool ok = true;
	try {
		Crypto::SymetricCrypto cr;
		if (_encryptionType == ENCRYPTED) {
			cr.setPassword(password);
		} else {
			cr.setPassword(DEFAULT_PASSWORD);
		}
		std::string uncrypted;
		cr.decrypt(_crypted, uncrypted);

		std::istringstream iss;
		iss.str(uncrypted);
		InArchive iarch(iss);
		iarch & strData;
		iarch & rawData;
		decrypted = true;
	}
	catch (...) {
		password = "";
		ok = false;
	}
	return ok;
}

}
